#include "stdafx.h"
#include "include/Gs.h"
#include "../Value.h"
#include "../String.h"
#include "../Object.h"

namespace Gs
{
	// Gets the type name of a specified type.
	GS_EXPIMP const char *GetValueTypeName(ValueType type)
	{
		switch(type)
		{
			case IntegerType:
				return "int";

			case FloatType:
				return "float";

			case StringType:
				return "string";

			case ObjectType:
				return "object";

			case FunctionType:
				return "function";

			case NilType:
				return "nil";

			case PointerType:
				return "pointer";

			default:
				return "unknown";
		}
	}

	// Initialises a new instance of the Value class.
	Value::Value()
		: _type(NilType)
	{
	}

	// Gets the type of the value.
	ValueType Value::GetType() const
	{
		return _type;
	}

	// Gets the type name of the value's type.
	const char *Value::GetTypeName() const
	{
		return GetValueTypeName(_type);
	}

	// Gets the value as an integer, converting if necessary.
	int Value::ToInt() const
	{
		switch(_type)
		{
			case IntegerType:
				return _i;

			case FloatType:
				return (int)_f;

			case StringType:
				return atoi(_s->GetCString());

			default:
				throw InvalidConversionException(GetTypeName(), "int");
		}
	}

	// Gets the value as a float, converting if necessary.
	float Value::ToFloat() const
	{
		switch(_type)
		{
			case IntegerType:
				return (float)_i;

			case FloatType:
				return _f;

			case StringType:
				return (float)atof(_s->GetCString());

			default:
				throw InvalidConversionException(GetTypeName(), "float");
		}
	}

	// Gets the value as a string, converting if necessary.
	IString *Value::ToString(IContext *context) const
	{
		switch(_type)
		{
			case IntegerType:
				char i[12];
				_itoa(_i, i, 10);
				return context->CreateString(i);

			case FloatType:
				char f[16];
				sprintf(f, "%.7g", _f);
				return context->CreateString(i);

			case StringType:
				return _s;

			default:
				return context->CreateString(GetTypeName());
		}
	}

	// Gets the value as an object.
	IObject *Value::ToObject() const
	{
		switch(_type)
		{
			case ObjectType:
				return _o;

			default:
				throw InvalidConversionException(GetTypeName(), "object");
		}
	}

	// Gets the value as a user pointer.
	UserPointer Value::ToUserPointer() const
	{
		switch(_type)
		{
			case PointerType:
				return _p;

			default:
				throw InvalidConversionException(GetTypeName(), "pointer");
		}
	}

	// Gets the value as a native function.
	NativeFunction Value::ToNativeFunction() const
	{
		switch(_type)
		{
			case FunctionType:
				return 0;

			default:
				throw InvalidConversionException( GetTypeName(), "native function pointer");
		}
	}

	// Gets the value as a function.
	Function *Value::ToFunction() const
	{
		switch(_type)
		{
			case FunctionType:
				return _fn;

			default:
				throw InvalidConversionException( GetTypeName(), "native function pointer");
		}
	}

	// Sets the value to a nil value.
	void Value::Set()
	{
		_type = NilType;
	}

	// Sets the value to an integer.
	void Value::Set(int i)
	{
		_type = IntegerType;
		_i = i;
	}

	// Sets the value to a float.
	void Value::Set(float f)
	{
		_type = FloatType;
		_f = f;
	}

	// Sets the value to a string.
	void Value::Set(String *s)
	{
		_type = StringType;
		_s = s;
	}

	// Sets the value to an object.
	void Value::Set(Object *o)
	{
		_type = ObjectType;
		_o = o;
	}

	// Sets the value to a function.
	void Value::Set(Function *f)
	{
		_type = FunctionType;
		_fn = f;
	}

	// Sets the value to a pointer.
	void Value::Set(UserPointer p)
	{
		_type = PointerType;
		_p = p;
	}

	// Sets the value to another value.
	void Value::Set(Value *v)
	{
		// we know the Value class is non-manipulated primitives only.
		memcpy(this, v, sizeof(Value));
	}
}